structure Id :> ID =
struct
  datatype t
    = T of {original : string,
            key : int,
            plist : PropertyList.t}
  
  fun bogus () = T {original = "", key = ~1, plist = PropertyList.new ()}

  fun compare (T {key = k1, ...}, T {key = k2, ...}) = Int.compare (k1, k2)

  structure Table = BinaryMapFn (type ord_key = string
                                 val compare = String.compare)
  val table : ((int * PropertyList.t) Table.map) ref = ref (Table.empty)
  
  val vars : int ref = ref 0
  fun newVars () =
      let val t = !vars
          val _ = if (!Control.doShowIdNums)
                  then print (String.concat ["the current internal id number is : ",
                                             Int.toString t,
                                             "\n"])
                  else ()
          val _ = vars := t + 1
      in  t
      end
  
  fun init () = vars := 0
  
  fun equals (T {key = k1, ...}, T {key = k2, ...}) = (k1 = k2)
  
  fun exists (l, id) =
      case l
       of [] => false
        | x :: xs =>
          if equals (x, id)
          then true
          else exists (xs, id)
  
  fun fromString s =
      let val t = !table
          val (k, p) = case Table.find (t, s)
                   of NONE =>
                      let val newKey = newVars ()
                          val newPlist = PropertyList.new ()
                          val _ = table := Table.insert (t, s, (newKey, newPlist))
                      in  (newKey, newPlist)
                      end
                    | SOME i => i
      in  T {original = s,
             key = k,
             plist = p}
      end      
  
  fun new () =
      let val k = newVars ()
          val plist = PropertyList.new ()
          val name = String.concat ["L..", Int.toString k]
          val _ = table := Table.insert (!table, name, (k, plist))
      in  T {original = name, key = k, plist = plist}
      end
      
  fun newWithPrefix s =
      let val k = newVars ()
          val plist = PropertyList.new ()
          val name = String.concat [s, "@L@", Int.toString k]
          val _ = table := Table.insert (!table, name, (k, plist))
      in  T {original = name, key = k, plist = plist}
      end 
  
  fun plist (T {plist, ...}) = plist
  
  fun println (T {key, ...}) = print (String.concat [Int.toString key, "\n"])
  
  fun toString (T {original, ...}) = original  
end
